import panorama from './panorama.svg'
import {
    globalLayer,
    globalTool
} from "../BQGIS-globalVar"

// 将数据添加至地图
export function addLayer(viewer, option) {
    if (!option) return
    let layer
    if (option.type === '全景图') {
        layer = addPano(viewer, option)
    } else if (option.type === '模型') {
        if (option.typecategory.indexOf("3dtiles") !== -1) {
            layer = add3dtilesLayer(viewer, option)
        } else if (option.typecategory === "gltf" || option.typecategory === "obj") {
            layer = addModel(viewer, option)
        }
    } else {
        layer = mars3d.LayerUtil.create(option)
        viewer.addLayer(layer);
    }
    return layer
}

function add3dtilesLayer(viewer, option) {
    const param = Object.assign({
        backFaceCulling: true,
        skipLevelOfDetail: true,
        baseScreenSpaceError: 256,
        maximumScreenSpaceError: 8, // 数值加大，能让最终成像变模糊
        skipScreenSpaceErrorFactor: 16,
        skipLevels: 1,
        immediatelyLoadDesiredLevelOfDetail: true,
        loadSiblings: false, // 如果为true则不会在已加载完概况房屋后，自动从中心开始超清化房屋
        cullRequestsWhileMoving: true,
        cullRequestsWhileMovingMultiplier: 60, // 值越小能够更快的剔除
        preloadWhenHidden: true,
        preferLeaves: true,
        maximumMemoryUsage: 1024, // 内存分配变小有利于倾斜摄影数据回收，提升性能体验
        progressiveResolutionHeightFraction: 0.2, // 数值偏于0能够让初始加载变得模糊
        dynamicScreenSpaceErrorDensity: 0.4, // 数值加大，能让周边加载变快
        dynamicScreenSpaceErrorFactor: 1, // dynamicScreenSpaceErrorDensity的因子
        dynamicScreenSpaceError: true, // 根据测试，有了这个后，会在真正的全屏加载完之后才清晰化房屋
        shadows: Cesium.ShadowMode.ENABLED, // 如果不投射，则日照分析和可视域分析不可用
        cullWithChildrenBounds: true,
        distanceDisplayCondition: new Cesium.DistanceDisplayCondition(0.0, 50000),
        maximumNumberOfLoadedTiles: 300000
    }, option)
    const layer = new mars3d.layer.TilesetLayer(param)
    layer.readyPromise.then(function (tileLayer) {
        tileLayer.tileset.dynamicScreenSpaceErrorDensity = param.dynamicScreenSpaceErrorDensity // 构造函数里 dynamicScreenSpaceErrorDensity 参数失效了，所以这里手动赋值
    })
    viewer.addLayer(layer);
    return layer
}

function addPano(viewer, option) {
    const position = option.position
    const layer = new mars3d.graphic.BillboardEntity({
        id: option.id,
        name: option.name,
        position: [position.lng, position.lat, position.alt],
        style: {
            image: panorama,
            width: 30,
            height: 30,
            horizontalOrigin: Cesium.HorizontalOrigin.CENTER,
            verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
            scaleByDistance: new Cesium.NearFarScalar(200, 1, 8000, 0),
            disableDepthTestDistance: 5000,
            label: {
                font: '14px sans-serif',
                text: option.name,
                pixelOffsetY: -40,
                scaleByDistance: new Cesium.NearFarScalar(200, 1, 8000, 0),
                disableDepthTestDistance: 5000,
            },
        },
        attr: {
            url: option.data
        }
    })
    if (!globalLayer.panoLayer) {
        globalLayer.panoLayer = new mars3d.layer.GraphicLayer()
        globalLayer.panoLayer.on(mars3d.EventType.click, data => {
            if (!globalTool.eventTarget) {
                globalTool.eventTarget = new mars3d.BaseClass() // viewer 自定义事件实例
            }
            globalTool.eventTarget.fire("clickPano", data)
        })
        viewer.addLayer(globalLayer.panoLayer)
    }
    globalLayer.panoLayer.addGraphic(layer)
    return layer
}

function addModel(viewer, option) {
    const position = option.position
    // const headingPitchRoll = Cesium.HeadingPitchRoll.fromDegrees(option.heading || 0, option.pitch || 0, option.roll || 0)
    // const orientation = Cesium.Quaternion.fromHeadingPitchRoll(headingPitchRoll)
    const layer = new mars3d.graphic.ModelEntity({
        id: option.id,
        name: option.name,
        // orientation,
        position: [position.lng, position.lat, position.alt],
        style: {
            heading: option.heading || 0,
            pitch: option.pitch || 0,
            roll: option.roll || 0,
            url: option.url,
        }
    })
    if (!globalLayer.modelLayer) {
        globalLayer.modelLayer = new mars3d.layer.GraphicLayer({
            contextmenuItems: [{
                text: '编辑',
                show: function (e) {
                    return e.graphic.type === 'model' && !e.graphic.isEditing
                },
                callback: function (e) {
                    e.graphic.once(mars3d.EventType.remove, function (event) { // 当模型被删除时，关闭编辑菜单
                        globalTool.eventTarget.fire('endEditModel', e.graphic.id)
                    });
                    e.graphic.startEditing()
                    globalTool.eventTarget.fire('startEditModel', e)
                },
            }]
        })
        viewer.addLayer(globalLayer.modelLayer)
    }
    globalLayer.modelLayer.addGraphic(layer)
    return layer
}


export function removeLayer(viewer, data) {
    const layer = getLayerByAttr(viewer, data)
    if (data.type === '全景图') {
        if (!globalLayer.panoLayer) return
        globalLayer.panoLayer.removeGraphic(layer)
    } else if (data.type === '模型') {
        if (!globalLayer.modelLayer) return
        globalLayer.modelLayer.removeGraphic(layer)
    } else {
        if (layer) {
            viewer.removeLayer(layer, true)
        }
    }
}


// 获取图层数据列表
export function getLayers(viewer) {
    return viewer.getLayers({
        basemaps: true, // 是否取config.json中的basempas
        layers: true // 是否取config.json中的layers
    })
}

// 获取所有的瓦片图层
export function getTileLayers(viewer) {
    return viewer.getTileLayers()
}

// 查找图层
export function getLayerByAttr(viewer, attr) {
    if (attr.type === '全景图') {
        return getPanoById(attr.id)
    } else if (attr.type === '模型') {
        if (attr.typecategory.indexOf("3dtiles") !== -1) {
            return getTileById(attr.id, viewer)
        } else if (attr.typecategory === "gltf" || attr.typecategory === "obj") {
            return getModelById(attr.id)
        }
    } else {
        return viewer.getLayerByAttr(attr.id, 'id')
    }
}

export function getTileById(id, viewer = window.viewer) {
    return viewer.getLayerByAttr(id, 'id')
}

export function getPanoById(id) {
    if (!globalLayer.panoLayer) return
    return globalLayer.panoLayer.getGraphicById(id)
}

export function getModelById(id) {
    if (!globalLayer.modelLayer) return
    return globalLayer.modelLayer.getGraphicById(id)
}

// 查询设置模型的经纬度与角度(暂未使用)
export function transform(layer, data) {
    if (!layer.transform) {
        let mt = Cesium.Matrix4.fromArray([
            1, 0, 0, 0,
            0, 1, 0, 0,
            0, 0, 1, 0,
            0, 0, 0, 1
        ])
        if (data.position) {
            const surface = mars3d.LngLatPoint.toCartesian([ // 经纬度转换为笛卡尔
                data.position.lng ? data.position.lng : layer.orginCenterPoint.lng,
                data.position.lat ? data.position.lat : layer.orginCenterPoint.lat,
                data.position.alt ? data.position.alt : layer.orginCenterPoint.alt
            ]);
            let translation = Cesium.Cartesian3.subtract( // 原始坐标与传入坐标的差值
                surface,
                layer.orginCenterPosition,
                new Cesium.Cartesian3()
            );
            mt = Cesium.Matrix4.clone(Cesium.Matrix4.fromTranslation(translation)); // 获取平移矩阵
        }
        layer.tileset.modelMatrix = mt;
        let mx = getMatrix4ByTransform( // x轴方向旋转矩阵
            layer,
            Cesium.Matrix3.fromRotationX(
                Cesium.Math.toRadians(data.rotation.x || 0)
            ),
            mt
        );
        let my = getMatrix4ByTransform( // y轴方向旋转矩阵
            layer,
            Cesium.Matrix3.fromRotationY(
                Cesium.Math.toRadians(data.rotation.y || 0)
            ),
            mt
        );
        let mz = getMatrix4ByTransform( // z轴方向旋转矩阵
            layer,
            Cesium.Matrix3.fromRotationZ(
                Cesium.Math.toRadians(data.rotation.z || 0)
            ),
            mt
        );
        Cesium.Matrix4.multiply(mx, mt, mx);
        Cesium.Matrix4.multiply(my, mx, my);
        Cesium.Matrix4.multiply(mz, my, mz);
        layer.setOptions({
            modelMatrix: mz
        });
    }
}

export function getMatrix4ByTransform(layer, transform, m) {
    // const pcenter = layer.tileset.boundingSphere.center // 模型当前的中心坐标
    const pcenter = Cesium.Matrix4.multiplyByPoint(
        layer.tileset.modelMatrix,
        layer.orginCenterPosition,
        new Cesium.Cartesian3()
    ); // 模型当前的中心坐标
    let transformMat = Cesium.Matrix4.fromArray(m); // 模型目前的仿射变换矩阵4*4
    let matRotation = Cesium.Matrix4.getMatrix3(
        transformMat,
        new Cesium.Matrix3()
    ); // 模型目前的旋转矩阵3*3
    let inverseMatRotation = Cesium.Matrix3.inverse(
        matRotation,
        new Cesium.Matrix3()
    ); // 模型旋转矩阵的逆
    let matTranslation = Cesium.Matrix4.getTranslation(
        transformMat,
        new Cesium.Cartesian3()
    ); // 获取仿射矩阵的平移部分

    let transformation = Cesium.Transforms.eastNorthUpToFixedFrame(pcenter); // 在原地位置建立x 轴指向当地的东方向，y 轴指向当地的北方向的仿射变换矩阵
    let transformRotation = Cesium.Matrix4.getMatrix3(
        transformation,
        new Cesium.Matrix3()
    ); // 获取坐标矩阵的
    let transformTranslation = Cesium.Matrix4.getTranslation(
        transformation,
        new Cesium.Cartesian3()
    ); // 在原地位置建立x 轴指向当地的东方向，y 轴指向当地的北方向的仿射变换矩阵

    let matToTranslation = Cesium.Cartesian3.subtract(
        matTranslation,
        transformTranslation,
        new Cesium.Cartesian3()
    );
    matToTranslation = Cesium.Matrix4.fromTranslation(
        matToTranslation,
        new Cesium.Matrix4()
    );

    let matToTransformation = Cesium.Matrix3.multiply(
        inverseMatRotation,
        transformRotation,
        new Cesium.Matrix3()
    );
    matToTransformation = Cesium.Matrix3.inverse(
        matToTransformation,
        new Cesium.Matrix3()
    );
    matToTransformation = Cesium.Matrix4.fromRotationTranslation(
        matToTransformation
    );

    let rotationTranslation = Cesium.Matrix4.fromRotationTranslation(transform);

    Cesium.Matrix4.multiply(transformation, rotationTranslation, transformation);
    Cesium.Matrix4.multiply(transformation, matToTransformation, transformation);
    Cesium.Matrix4.multiply(transformation, matToTranslation, transformation);
    return transformation;
}


// 模型偏移(设置北，东，高的偏移量，暂时未使用, 因为设置偏移矩阵时会导致mars3d的position，rotation两个参数失效，该功能与设置经纬度的功能冲突)
export function translate({
    offseteast,
    offsetnorth,
    offsetheight
}, tileset) {
    // 设置偏移距离(m)
    let transform = Cesium.Transforms.eastNorthUpToFixedFrame(tileset.boundingSphere.center)
    let m = Cesium.Matrix4.setTranslation(Cesium.Matrix4.IDENTITY, new Cesium.Cartesian3(offseteast ? Number(offseteast) : 0, offsetnorth ? Number(offsetnorth) : 0, offsetheight ? Number(offsetheight) : 0), new Cesium.Matrix4())
    let modelMatrix = Cesium.Matrix4.multiply(transform, m, transform)
    let target = new Cesium.Cartesian3()
    Cesium.Matrix4.getTranslation(modelMatrix, target)
    let translation = Cesium.Cartesian3.subtract(
        target,
        tileset.boundingSphere.center,
        new Cesium.Cartesian3()
    );
    tileset.modelMatrix = Cesium.Matrix4.fromTranslation(translation)
}